﻿namespace Example.Xml.Xsl
{
    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Text;
    using System.Xml;
    using System.Xml.XPath;
    using System.Xml.Xsl;
    using Example.IO;

    [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Stylesheet", Justification = "This is the correct spelling.")]
    public class Stylesheet
    {
        private XslCompiledTransform _compiled;

        public Stylesheet(Uri location)
        {
            Compiled = ToXslCompiledTransform(location);
        }

        private XslCompiledTransform Compiled
        {
            get
            {
                return _compiled;
            }

            set
            {
                if (null == value)
                {
                    throw new ArgumentNullException("value");
                }

                _compiled = value;
            }
        }

        public string Transform(IXPathNavigable xml)
        {
            return Transform(xml, Encoding.UTF8);
        }

        public string Transform(IXPathNavigable xml, Encoding encoding)
        {
            if (xml == null)
            {
                throw new ArgumentNullException("xml");
            }

            var buffer = new StringBuilder();

            using (var encoded = new EncodedStringWriter(buffer, encoding))
            {
                using (var writer = XmlWriter.Create(encoded, Compiled.OutputSettings))
                {
                    Compiled.Transform(xml, writer);
                }
            }

            return buffer.ToString();
        }

        private static XslCompiledTransform ToXslCompiledTransform(Uri location)
        {
            if (location == null)
            {
                throw new ArgumentNullException("location");
            }

            XslCompiledTransform compiled;
            var settings = new XmlReaderSettings
            {
                DtdProcessing = DtdProcessing.Parse,
                CheckCharacters = false
            };

            using (var reader = XmlReader.Create(location.IsAbsoluteUri ? location.AbsoluteUri : location.OriginalString, settings))
            {
                compiled = new XslCompiledTransform();
                compiled.Load(reader, new XsltSettings(true, true), new XmlUrlResolver());
            }

            return compiled;
        }
    }
}